package cn.iocoder.yudao.module.reading.service.community;

import cn.iocoder.yudao.module.reading.controller.app.community.vo.common.LimitCheckRespVO;
import cn.iocoder.yudao.module.reading.dal.dataobject.community.CommunityUserLimitDO;
import cn.iocoder.yudao.module.reading.dal.mysql.community.CommunityUserLimitMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import jakarta.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

/**
 * 社区频控限制服务实现类
 *
 * @author 芋道源码
 */
@Service
@Slf4j
public class CommunityLimitServiceImpl implements CommunityLimitService {

    @Resource
    private CommunityUserLimitMapper userLimitMapper;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    // 发帖频控：每天最多10条
    private static final int POST_MAX_COUNT_PER_DAY = 10;
    // 评论频控：每分钟最多6条
    private static final int COMMENT_MAX_COUNT_PER_MINUTE = 6;

    @Override
    public LimitCheckRespVO checkPostLimit(Long userId) {
        LocalDate today = LocalDate.now();
        CommunityUserLimitDO limit = userLimitMapper.selectByUserIdAndTypeAndDate(userId, "post", today);
        
        LimitCheckRespVO result = new LimitCheckRespVO();
        
        if (limit == null) {
            // 今天还没有发帖记录
            result.setCanOperate(true);
            result.setRemainingCount(POST_MAX_COUNT_PER_DAY);
            result.setResetTime(LocalDateTime.of(today.plusDays(1), LocalTime.MIN));
        } else {
            // 检查是否超过限制
            boolean canPost = limit.getCurrentCount() < limit.getMaxCount();
            result.setCanOperate(canPost);
            // 确保剩余次数不为负数
            int remainingCount = Math.max(0, limit.getMaxCount() - limit.getCurrentCount());
            result.setRemainingCount(remainingCount);
            result.setResetTime(limit.getResetTime());

            if (!canPost) {
                result.setMessage("今日发帖次数已达上限，明天再来吧！");
            }
        }
        
        return result;
    }

    @Override
    public LimitCheckRespVO checkCommentLimit(Long userId) {
        // 使用Redis实现分钟级频控
        String redisKey = "community:comment:limit:" + userId;
        LocalDateTime now = LocalDateTime.now();

        // 获取当前分钟内的评论次数
        String currentCountStr = stringRedisTemplate.opsForValue().get(redisKey);
        int currentCount = currentCountStr != null ? Integer.parseInt(currentCountStr) : 0;

        LimitCheckRespVO result = new LimitCheckRespVO();

        if (currentCount >= COMMENT_MAX_COUNT_PER_MINUTE) {
            // 超过限制
            result.setCanOperate(false);
            result.setRemainingCount(0);
            result.setResetTime(now.plusMinutes(1).withSecond(0).withNano(0));
            result.setMessage("评论过于频繁，请稍后再试！");
        } else {
            // 未超过限制
            result.setCanOperate(true);
            result.setRemainingCount(COMMENT_MAX_COUNT_PER_MINUTE - currentCount);
            result.setResetTime(now.plusMinutes(1).withSecond(0).withNano(0));
        }

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void recordPostAction(Long userId) {
        LocalDate today = LocalDate.now();
        CommunityUserLimitDO limit = userLimitMapper.selectByUserIdAndTypeAndDate(userId, "post", today);
        
        if (limit == null) {
            // 创建新的频控记录
            limit = CommunityUserLimitDO.builder()
                    .userId(userId)
                    .limitType("post")
                    .limitDate(today)
                    .currentCount(1)
                    .maxCount(POST_MAX_COUNT_PER_DAY)
                    .resetTime(LocalDateTime.of(today.plusDays(1), LocalTime.MIN))
                    .build();
            userLimitMapper.insert(limit);
        } else {
            // 更新现有记录
            limit.setCurrentCount(limit.getCurrentCount() + 1);
            userLimitMapper.updateById(limit);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void recordCommentAction(Long userId) {
        // 1. 更新Redis中的分钟级计数
        String redisKey = "community:comment:limit:" + userId;
        Long currentCount = stringRedisTemplate.opsForValue().increment(redisKey);

        // 设置过期时间为1分钟
        if (currentCount == 1) {
            stringRedisTemplate.expire(redisKey, java.time.Duration.ofMinutes(1));
        }

        // 2. 更新数据库中的日统计（用于统计分析）
        LocalDate today = LocalDate.now();
        CommunityUserLimitDO limit = userLimitMapper.selectByUserIdAndTypeAndDate(userId, "comment", today);

        if (limit == null) {
            // 创建新的频控记录
            limit = CommunityUserLimitDO.builder()
                    .userId(userId)
                    .limitType("comment")
                    .limitDate(today)
                    .currentCount(1)
                    .maxCount(COMMENT_MAX_COUNT_PER_MINUTE)
                    .resetTime(LocalDateTime.of(today.plusDays(1), LocalTime.MIN))
                    .build();
            userLimitMapper.insert(limit);
        } else {
            // 更新现有记录
            limit.setCurrentCount(limit.getCurrentCount() + 1);
            userLimitMapper.updateById(limit);
        }
    }

    @Override
    public void resetUserPostLimit(Long userId) {
        LocalDate today = LocalDate.now();
        CommunityUserLimitDO limit = userLimitMapper.selectByUserIdAndTypeAndDate(userId, "post", today);

        if (limit != null) {
            // 重置当前次数为0
            limit.setCurrentCount(0);
            userLimitMapper.updateById(limit);
        }
        // 如果没有记录，不需要做任何操作
    }

}
